/** eslint-disable */

function thousands(number, to_integer, precision) {
  var num_str = to_integer
    ? parseInt(number).toString()
    : number.toFixed(precision);
  var parts = num_str.split(".");
  var exp = /\d{1,3}(?=(\d{3})+(\.\d*)?$)/g;
  return (
    parts[0].replace(exp, "$&,") +
    (parts.length > 1 ? "." + parts[1].replace(/\\,/g, "") : "")
  );
}

function formatDateTime(date_time, fmt) {
  if (fmt == undefined || fmt == null) {
    fmt = "yyyy-MM-dd hh:mm:ss";
  }

  var o = {
    "M+": date_time.getMonth() + 1,
    "d+": date_time.getDate(),
    "h+": date_time.getHours(),
    "m+": date_time.getMinutes(),
    "s+": date_time.getSeconds(),
    "q+": Math.floor((date_time.getMonth() + 3) / 3),
    S: date_time.getMilliseconds()
  };

  if (/(y+)/.test(fmt)) {
    fmt = fmt.replace(
      RegExp.$1,
      (date_time.getFullYear() + "").substr(4 - RegExp.$1.length)
    );
  }

  for (var k in o) {
    if (new RegExp("(" + k + ")").test(fmt)) {
      fmt = fmt.replace(
        RegExp.$1,
        RegExp.$1.length == 1 ? o[k] : ("00" + o[k]).substr(("" + o[k]).length)
      );
    }
  }

  return fmt;
}

function distinctArray(arr, predicate) {
  var is_func = typeof predicate == "function";
  var distincted = [];

  for (var idx = 0; idx < arr.length; idx++) {
    var ele = arr[idx];
    if (distincted.indexOf(is_func ? predicate(ele) : ele) < 0) {
      distincted.push(is_func ? predicate(ele) : ele);
    }
  }
  return distincted;
}

function summarizeFiled(arr, predicate) {
  var total = 0;
  var is_func = typeof predicate == "function";

  for (var idx = 0; idx < arr.length; idx++) {
    var ele = arr[idx];
    total += is_func ? predicate(ele) : ele;
  }
  return total;
}

function groupByMembers(arr, predicate) {
  if (typeof predicate != "function") {
    return {};
  }

  var map = {};
  for (var idx = 0; idx < arr.length; idx++) {
    var ele = arr[idx];
    var key = predicate(ele);
    if (map[key] == undefined) {
      map[key] = [];
    }
    map[key].push(ele);
  }

  return map;
}

function removeMembers(arr, predicate, only_first) {
  if (typeof predicate != "function") {
    return arr;
  }

  var pending_removing_idxes = [];
  for (var idx = 0; idx < arr.length; idx++) {
    if (predicate(arr[idx]) === true) {
      pending_removing_idxes.push(idx);
      if (only_first === true) {
        break;
      }
    }
  }
  // remove expected element one by one
  while (pending_removing_idxes.length > 0) {
    arr.splice(pending_removing_idxes.pop(), 1);
  }

  return arr;
}

function findMaxMember(arr, predicate) {
  if (arr.length == 0) {
    throw new Error("length equals 0");
  } else if (arr.length == 1) {
    return predicate(arr[0]);
  }
  var max = predicate(arr[0]);
  for (var idx = 1; idx < arr.length; idx++) {
    if (max < predicate(arr[idx])) {
      max = predicate(arr[idx]);
    }
  }
  return max;
}

function findMinMember(arr, predicate) {
  if (arr.length == 0) {
    throw new Error("length equals 0");
  } else if (arr.length == 1) {
    return predicate(arr[0]);
  }

  var min = predicate(arr[0]);
  for (var idx = 1; idx < arr.length; idx++) {
    if (min > predicate(arr[idx])) {
      min = predicate(arr[idx]);
    }
  }

  return min;
}

function mergeArrays(first, second) {
  if (!(second instanceof Array) || second.length == 0) {
    return first;
  }
  for (var i = 0; i < second.length; i++) {
    first.push(second[i]);
  }
  return first;
}

/**
 * extend Number prototype
 */

Number.prototype.number2Str = function(precision) {
  return this.toFixed(precision !== undefined ? precision : 2);
};
// thousands into an integer
Number.prototype.thousands = function() {
  return thousands(this, true);
};
// thousands into a decimal
Number.prototype.thousandsDecimal = function(precision) {
  return thousands(this, false, precision >= 2 ? parseInt(precision) : 2);
};
// cast a number (actually an UTC time)
Number.prototype.formatDateTime = function(fmt) {
  var int_me = parseInt(this);
  return int_me.toString().length == 13
    ? formatDateTime(new Date(int_me), fmt)
    : this;
};

/**
 * extend Date prototype
 */

Date.prototype.format = function(fmt) {
  return formatDateTime(this, fmt);
};
Date.prototype.addYears = function(years) {
  return Date.createDate(this, "year", years);
};
Date.prototype.addMonths = function(months) {
  return Date.createDate(this, "month", months);
};
Date.prototype.addDays = function(days) {
  return Date.createDate(this, "day", days);
};
Date.prototype.addHours = function(hours) {
  return Date.createDate(this, "hour", hours);
};
Date.prototype.addMinutes = function(minutes) {
  return Date.createDate(this, "minute", minutes);
};
Date.prototype.addSeconds = function(seconds) {
  return Date.createDate(this, "second", seconds);
};
Date.createDate = function(instance, type, change) {
  switch (type) {
    case "year":
      return new Date(
        instance.getFullYear() + change,
        instance.getMonth(),
        instance.getDate(),
        instance.getHours(),
        instance.getMinutes(),
        instance.getSeconds(),
        instance.getMilliseconds()
      );
    case "month":
      return new Date(
        instance.getFullYear(),
        instance.getMonth() - 1 + change,
        instance.getDate(),
        instance.getHours(),
        instance.getMinutes(),
        instance.getSeconds(),
        instance.getMilliseconds()
      );
    case "day":
      return new Date(
        instance.getFullYear(),
        instance.getMonth(),
        instance.getDate() + change,
        instance.getHours(),
        instance.getMinutes(),
        instance.getSeconds(),
        instance.getMilliseconds()
      );
    case "hour":
      return new Date(
        instance.getFullYear(),
        instance.getMonth(),
        instance.getDate(),
        instance.getHours() + change,
        instance.getMinutes(),
        instance.getSeconds(),
        instance.getMilliseconds()
      );
    case "minute":
      return new Date(
        instance.getFullYear(),
        instance.getMonth(),
        instance.getDate(),
        instance.getHours(),
        instance.getMinutes() + change,
        instance.getSeconds(),
        instance.getMilliseconds()
      );
    case "second":
      return new Date(
        instance.getFullYear(),
        instance.getMonth(),
        instance.getDate(),
        instance.getHours(),
        instance.getMinutes(),
        instance.getSeconds() + change,
        instance.getMilliseconds()
      );
  }
};

/**
 * extend Array prototype
 */

/**
 * distribute a nick name for built-in methods
 */
Array.prototype.contains = function(predicate) {
  return this.findIndex(predicate) >= 0;
};
Array.prototype.first = function(predicate) {
  return this.find(predicate);
};
Array.prototype.select = function(predicate) {
  return this.filter(predicate);
};
Array.prototype.orderBy = function(comparer_predicate) {
  return this.sort(comparer_predicate);
};
Array.prototype.orderBy = function(delegate) {
  return this._orderBy(delegate, "asc");
};
Array.prototype.orderByDescending = function(delegate) {
  return this._orderBy(delegate, "desc");
};
Array.prototype.orderByDesc = Array.prototype.orderByDescending;
Array.prototype._orderBy = function(delegate, direction) {
  if (this.length <= 1) {
    return this;
  }
  var isFunction = typeof delegate == "function";
  var tmp;
  for (var i = 0; i < this.length - 1; i++) {
    for (var j = i + 1; j < this.length; j++) {
      var first = this[i];
      var next = this[j];
      var result;
      if (direction == "asc") {
        result = isFunction ? delegate(first) > delegate(next) : first > next;
      } else {
        result = isFunction ? delegate(first) < delegate(next) : first < next;
      }
      if (result) {
        tmp = this[i];
        this[i] = this[j];
        this[j] = tmp;
      }
    }
  }
  return this;
};

Array.prototype.distinct = function(predicate) {
  return distinctArray(this, predicate);
};
Array.prototype.sum = function(predicate) {
  return summarizeFiled(this, predicate);
};
Array.prototype.groupBy = function(predicate) {
  return groupByMembers(this, predicate);
};
Array.prototype.remove = function(predicate, only_first) {
  return removeMembers(this, predicate, only_first);
};
Array.prototype.max = function(predicate) {
  return findMaxMember(this, predicate);
};
Array.prototype.min = function(predicate) {
  return findMinMember(this, predicate);
};

Array.prototype.last = function(total) {
  if (this.length == 0 || typeof total != "number" || total < 1) {
    return [];
  }
  total = parseInt(total);
  if (total == 1) {
    return this[this.length - 1];
  } else {
    return total > this.length
      ? this.slice(0)
      : this.slice(this.length - total);
  }
};
Array.prototype.clear = function() {
  while (this.length > 0) {
    this.pop();
  }
};
Array.prototype.merge = function(others) {
  return mergeArrays(this, others);
};

Blob.prototype.saveAs = function(filename) {
  var urlObject = URL || webkitURL;
  if (!urlObject) {
    throw "当前JS环境无法导出!";
  }
  if (!filename) {
    console.error("export filename is requried");
    return;
  }
  // 对于IE10以上
  if (navigator.msSaveBlob) {
    navigator.msSaveBlob(this, filename);
  } else {
    var save_link = document.createElementNS(
      "http://www.w3.org/1999/xhtml",
      "a"
    );
    save_link.href = urlObject.createObjectURL(this);
    save_link.download = filename;
    var ev = document.createEvent("MouseEvents");
    ev.initMouseEvent(
      "click",
      true,
      false,
      window,
      0,
      0,
      0,
      0,
      0,
      false,
      false,
      false,
      false,
      0,
      null
    );
    save_link.dispatchEvent(ev);
  }
};

module.exports = {};
